package pathways.Database.Specialized.Visual;

/**
 * Title:        Pathways
 * Description:  Pure Java version of the Pathways Project.
 * Copyright:    Copyright (c) 2002
 * Company:      Ants Technologies
 * @author Veejay Sani
 * @version 1.0
 */

import java.awt.Frame;
import java.awt.Rectangle;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.swing.AbstractListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import pathways.CCompound;
import pathways.CEnzyme;
import pathways.CReaction;
import pathways.CSubstrate;
import pathways.Database.Implementation.CDatabase;
import pathways.util.CUtil;
import pathways.util.Debug.CDebug;
 
public class CDBSVSearchReaction extends JDialog
{
  JLabel lblEnterSubstrate = new JLabel();
  JTextField txtSearchSubstrate = new JTextField();
  JButton cmdClear = new JButton();
  JScrollPane scrollPaneSubs = new JScrollPane();
  JScrollPane scrollPaneEnzymes = new JScrollPane();
  JScrollPane scrollPaneProds = new JScrollPane();
  JList lstSubs = new JList();
  JList lstEnzymes = new JList();
  JList lstProds = new JList();
  JLabel lblSubstrates = new JLabel();
  JLabel lblEnzymes = new JLabel();
  JLabel lblProducts = new JLabel();
  JButton cmdOK = new JButton();
  JButton cmdCancel = new JButton();
    
  CMyRSListModel mdlSubs;
  CMyRSListModel mdlEnzymes;
  CMyRSListModel mdlProds;
  
  CDatabase db;
  Rectangle subRect;
  Rectangle prodRect;
  int connectingFrom;
  int connectingTo;
  CReaction reaction;
    
  public CDBSVSearchReaction(CDatabase database, Frame owner, 
                             Rectangle subRectangle, Rectangle prodRectangle,
                             int connectingfrom, int connectingto)
  {
    super(owner,true);
    
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
    
    setSize(770,500);
      
    db = database;
    subRect = subRectangle;
    prodRect = prodRectangle;
    connectingFrom = connectingfrom;
    connectingTo = connectingto;  
  }
  
  private void jbInit() throws Exception
  {
    lblEnterSubstrate.setText("Enter Substrate:");
    lblEnterSubstrate.setBounds(new Rectangle(6, 10, 100, 20));
    this.getContentPane().setLayout(null);
    txtSearchSubstrate.setBounds(new Rectangle(103, 14, 124, 22));
    txtSearchSubstrate.addKeyListener(new java.awt.event.KeyAdapter()
    {
      public void keyReleased(KeyEvent e)
      {
        txtSearchSubstrate_keyReleased(e);
      }
    });
    cmdClear.setBounds(new Rectangle(265, 13, 75, 24));
    cmdClear.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdClear_actionPerformed(e);
      }
    });
    cmdClear.setText("Clear");
    scrollPaneSubs.setBounds(new Rectangle(12, 90, 241, 306));
    scrollPaneEnzymes.setBounds(new Rectangle(264, 90, 241, 306));
    scrollPaneProds.setBounds(new Rectangle(518, 90, 241, 306));
    lblSubstrates.setFont(new java.awt.Font("Dialog", 1, 16));
    lblSubstrates.setForeground(SystemColor.activeCaption);
    lblSubstrates.setText("Substrates:");
    lblSubstrates.setBounds(new Rectangle(75, 61, 103, 26));
    lblEnzymes.setBounds(new Rectangle(335, 61, 103, 26));
    lblEnzymes.setText("Enzymes:");
    lblEnzymes.setForeground(SystemColor.activeCaption);
    lblEnzymes.setFont(new java.awt.Font("Dialog", 1, 16));
    lblProducts.setBounds(new Rectangle(589, 61, 103, 26));
    lblProducts.setText("Products:");
    lblProducts.setForeground(SystemColor.activeCaption);
    lblProducts.setFont(new java.awt.Font("Dialog", 1, 16));
    cmdOK.setText("OK");
    cmdOK.setBounds(new Rectangle(571, 414, 77, 26));
    cmdOK.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdOK_actionPerformed(e);
      }
    });
    cmdCancel.setBounds(new Rectangle(661, 414, 77, 26));
    cmdCancel.setText("Cancel");
    cmdCancel.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        cmdCancel_actionPerformed(e);
      }
    });
    this.setModal(true);
    this.setResizable(false);
    lstSubs.addMouseListener(new java.awt.event.MouseAdapter()
    {
      public void mouseClicked(MouseEvent e)
      {
        lstSubs_mouseClicked(e);
      }
    });
    lstEnzymes.addMouseListener(new java.awt.event.MouseAdapter()
    {
      public void mouseClicked(MouseEvent e)
      {
        lstEnzymes_mouseClicked(e);
      }
    });
    lstProds.addMouseListener(new java.awt.event.MouseAdapter()
    {
      public void mouseClicked(MouseEvent e)
      {
        lstProds_mouseClicked(e);
      }
    });
    this.getContentPane().add(lblEnterSubstrate, null);
    this.getContentPane().add(txtSearchSubstrate, null);
    this.getContentPane().add(scrollPaneEnzymes, null);
    this.getContentPane().add(scrollPaneSubs, null);
    this.getContentPane().add(scrollPaneProds, null);
    scrollPaneProds.getViewport().add(lstProds, null);
    this.getContentPane().add(lblSubstrates, null);
    scrollPaneSubs.getViewport().add(lstSubs, null);
    scrollPaneEnzymes.getViewport().add(lstEnzymes, null);
    this.getContentPane().add(lblEnzymes, null);
    this.getContentPane().add(lblProducts, null);
    this.getContentPane().add(cmdOK, null);
    this.getContentPane().add(cmdCancel, null);
    this.getContentPane().add(cmdClear, null);
  }

  void txtSearchSubstrate_keyReleased(KeyEvent e)
  {
    if (e.getKeyCode() == KeyEvent.VK_ENTER)
    {
      ResultSet rs = db.getSelect().getCompoundsMatchingName(this.txtSearchSubstrate.getText(), CSearchCompound.FILTER_SUBSTRATES);
      
      this.mdlSubs = new CMyRSListModel(rs,2);
      this.lstSubs.setModel(this.mdlSubs);
      
      this.mdlEnzymes = new CMyRSListModel(null,2);
      this.lstEnzymes.setModel(this.mdlEnzymes);
      
      this.mdlProds = new CMyRSListModel(null,2);
      this.lstProds.setModel(this.mdlProds);
    }
  }

  void lstSubs_mouseClicked(MouseEvent e)
  {
    int index = this.lstSubs.getSelectedIndex();
    
    if (index >= 0)
    {
      CCompound c = this.mdlSubs.getCompound(index);
      
      int[] temp = {0};
      
      ResultSet rs = db.getSelect().getEnzymesBySubstrateAndProduct(c.getID(),0,temp);
      this.mdlEnzymes = new CMyRSListModel(rs,2);
      this.lstEnzymes.setModel(this.mdlEnzymes);
      
      rs = db.getSelect().getProdcutsBySubstrateAndEnzyme(c.getID(),0,temp);
      this.mdlProds = new CMyRSListModel(rs,2);
      this.lstProds.setModel(this.mdlProds);  
    }
  }

  void lstEnzymes_mouseClicked(MouseEvent e)
  {
    int subIndex = this.lstSubs.getSelectedIndex();
    int index = this.lstEnzymes.getSelectedIndex();
    int prodIndex = this.lstProds.getSelectedIndex();
    
    if (index >= 0)
    {
      if (prodIndex < 0)
      {
        CCompound subCmpd = this.mdlSubs.getCompound(subIndex);
        CCompound enzymeCmpd = this.mdlEnzymes.getCompound(index);
        
	int[] temp = {0};
        ResultSet rs = db.getSelect().getProdcutsBySubstrateAndEnzyme(subCmpd.getID(),enzymeCmpd.getID(),temp);
        
        this.mdlProds = new CMyRSListModel(rs,2);
        this.lstProds.setModel(this.mdlProds);  
      }   
    }
  }
  
  void lstProds_mouseClicked(MouseEvent e)
  {
    int subIndex = this.lstSubs.getSelectedIndex();
    int enzymeIndex = this.lstEnzymes.getSelectedIndex();
    int prodIndex = this.lstProds.getSelectedIndex();
    
    if (prodIndex >= 0)
    {
      if (enzymeIndex < 0)
      {
        CCompound subCmpd = this.mdlSubs.getCompound(subIndex);
        CCompound prodCmpd = this.mdlProds.getCompound(prodIndex);
        
	int[] temp = {0};
        ResultSet rs = db.getSelect().getEnzymesBySubstrateAndProduct(subCmpd.getID(),prodCmpd.getID(),temp);
        
        this.mdlEnzymes = new CMyRSListModel(rs,2);
        this.lstEnzymes.setModel(this.mdlEnzymes);  
      }   
    }
  }

  void cmdClear_actionPerformed(ActionEvent e)
  {
    this.txtSearchSubstrate.setText("");
    
    this.mdlSubs = new CMyRSListModel(null,2);
    this.lstSubs.setModel(this.mdlSubs);
    
    this.mdlEnzymes = new CMyRSListModel(null,2);
    this.lstEnzymes.setModel(this.mdlEnzymes);
    
    this.mdlProds = new CMyRSListModel(null,2);
    this.lstProds.setModel(this.mdlProds);
    
    this.txtSearchSubstrate.requestFocus();
  }

  void cmdOK_actionPerformed(ActionEvent e)
  {
    if (isOK())
    {
      int subIndex = this.lstSubs.getSelectedIndex();
      int enzymeIndex = this.lstEnzymes.getSelectedIndex();
      int prodIndex = this.lstProds.getSelectedIndex();
      
      CCompound subCmpd = this.mdlSubs.getCompound(subIndex);
      CCompound enzymeCmpd = this.mdlEnzymes.getCompound(enzymeIndex);
      CCompound prodCmpd = this.mdlProds.getCompound(prodIndex);
      
      CSubstrate sub = new CSubstrate(subCmpd.getName(),subCmpd.getID(),subRect);
      CSubstrate prod = new CSubstrate(prodCmpd.getName(),prodCmpd.getID(),prodRect);
      CEnzyme enzyme = new CEnzyme(enzymeCmpd.getName(),enzymeCmpd.getID());
      
      ResultSet rs = db.getSelect().getReaction(sub.getID(),enzyme.getID(),prod.getID());
      long rxnID = 0;
      
      try {
        rs.next();
        rxnID = rs.getLong(1);
      } catch(SQLException excep) {
        rxnID = 0;
        CDebug.println(this, "cmdOK_actionPerformed() Exception: " + excep.toString());
        return; 
      }
      
      reaction = new CReaction(sub,enzyme,prod,connectingFrom,connectingTo,rxnID);
      
      reaction.read(rxnID,db);
      
      this.hide();
    }
  }
  
  private void selectIfOnlyOneItemInLists()
  {
    // if substrate not selected then return
    // if both selected then return
    // if one enz and one prod then select both
    // if enz selected then select if one prod
    // if prod selected then select if one enz
    int enzymeIndex = this.lstEnzymes.getSelectedIndex();
    int prodIndex = this.lstProds.getSelectedIndex();
    
    if (this.lstSubs.getSelectedIndex() < 0)
       return;
    
    if (enzymeIndex >= 0 && prodIndex >= 0)
       return;
       
    int enzymeCount = this.lstEnzymes.getModel().getSize();
    int prodCount = this.lstProds.getModel().getSize();
    
    if (enzymeCount == 1 && prodCount == 1)
    {
      this.lstEnzymes.setSelectedIndex(0);
      this.lstProds.setSelectedIndex(0);
    }
    
    if (enzymeIndex >= 0 && prodCount == 1)
    {
       this.lstProds.setSelectedIndex(0);
       return;
    }
    
    if (prodIndex >=0 && enzymeCount == 1)
    {
      this.lstEnzymes.setSelectedIndex(0);
      return; 
    }
    
  }
  
  public CReaction getReaction()
  {
    return reaction;  
  }
  
  private boolean isOK()
  {
    selectIfOnlyOneItemInLists();
    
    int subIndex = this.lstSubs.getSelectedIndex();
    int enzymeIndex = this.lstEnzymes.getSelectedIndex();
    int prodIndex = this.lstProds.getSelectedIndex();
    
    if (subIndex < 0)
    {
      JOptionPane.showMessageDialog(this,"Please select a substrate.");
      return false;
    }
    
    if (enzymeIndex < 0)
    {
      JOptionPane.showMessageDialog(this,"Please select an enzyme.");
      return false;
    }
    
    if (prodIndex < 0)
    {
      JOptionPane.showMessageDialog(this,"Please select a product.");
      return false;
    }

    return true;
  }

  void cmdCancel_actionPerformed(ActionEvent e)
  {
    reaction = null;
    this.hide();
  }
}

class CMyRSListModel extends AbstractListModel
{
  public CMyRSListModel(ResultSet set, int column)
  {
    rs = set;
    this.column = column;
    
    try
    {
      if (rs != null)
         size = CUtil.getResultSetRowCount(rs);
      
    }
    catch(SQLException e)
    {
       CDebug.println(this, "Unable to get the size of the recordset. Error: " + e.toString());
       
       System.err.println("Fatal Error: Connection to database was lost. Please try again.");
              
       size = 0;
    }
  }
  
  public Object getElementAt(int index)
  {
    try
    {
      rs.absolute(index+1);
      return rs.getObject(column);
    }
    catch (SQLException e)
    {
      System.err.println("Fatal Error: Connection to database was lost.  Please try again.");
    }
    
    return null;
  }
  
  public int getSize()
  {      
    return size;
  }
  
  public ResultSet getData()
  {
    return rs;
  }
  
  public void setData(ResultSet r)
  {
    rs = r;
    
    if (rs != null)
    {  
      try{
       size = CUtil.getResultSetRowCount(rs);
      } catch (SQLException e) { size = 0;}
    }
    else
      size = 0;  
  }
  
  public CCompound getCompound(int index)
  {
    try
    {
      rs.absolute(index+1);
      return (new CCompound(rs.getString(column),rs.getLong(column-1)));
    }
    catch (SQLException e)
    {
      System.err.println("Fatal Error: Connection to database was lost.  Please try again.");
    }
    
    return null;
  }
  
  private ResultSet rs;
  private int size;
  private int column;
}